﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;

namespace konstruivania_grapf_test2
{
    internal class vershuna : Window
    {

        public Point p;
        public int ident;
        public int dist;
        public Ellipse blueRectangle;
        public Label lb_vershunu;
        private main_control rez;
        public int x, y, id;
        private List<int> mas_rebers_index = new List<int>();

        public vershuna(int _x, int _y, int _id, main_control a) //ініціалізація початкових даних вершини
        {
            x = _x;
            y = _y;
            id = _id;
            rez = a;
            ident = id;
            p.X = x;
            p.Y = y;
            add_vershuna();
        }

        public void add_redbrechko(object sender, RoutedEventArgs e) //створення ребра у графі
        {
            Ellipse testik = (Ellipse) sender;
            if (rez.editing)
            {
                if (rez.enable_conect == true)
                {
                    if (rez.from == -1)
                    {
                        rez.from = int.Parse(testik.Name.ToString().Replace("n", ""));
                        blueRectangle.StrokeThickness = 4;
                    }
                    else if (rez.to == -1)
                    {
                        rez.to = int.Parse(testik.Name.ToString().Replace("n", ""));
                        blueRectangle.StrokeThickness = 6;
                        rez.add_rebro();
                        rez.enable_conect = false;
                    }
                }
            }
        }

        protected void lb_vershunu_MouseDown(object sender, RoutedEventArgs e)
            //виділення красним найкоротший шлях від вибраної вершини до головної
        {
            List<int> value_versh = new List<int>();
            List<int> id_rebra = new List<int>();
            List<int> nomer_vershunu = new List<int>();
            var allEdges = new List<Edge>();
            var allVertex = new List<vershuna>();
            //var allVertex = new LisList<Edge>();
            int vudilena_verchuna = int.Parse(lb_vershunu.Uid);
            int destinationEdge = int.Parse(lb_vershunu.Uid);
            int fromEdge = rez.first;

            SolidColorBrush redBrush = new SolidColorBrush();
            redBrush.Color = Colors.Red;
            SolidColorBrush blackBrush = new SolidColorBrush();
            blackBrush.Color = Colors.Black;
            for (int i = 0; i < rez.rebra.Count; i++) //красимо все линии в чорный 
            {
                rez.rebra[i].rebro.Stroke = blackBrush;
            }

            //-----------------------------------------------------------------

            var node = new Node {Edge = new Edge {from = vudilena_verchuna}};
            ExpandGraphRecursive(node, destinationEdge, destinationEdge, fromEdge, -1);
            var allPathes = new List<List<Edge>>();

            foreach (var child in node.Childs)
            {
                var path = GetPath(child, fromEdge);
                if (path != null)
                {
                    allPathes.Add(path.ToList());
                }
            }


            while (true)
            {
                var walkedEdges = new List<Edge>();
                for (int i = 0; i < rez.rebra.Count; i++)
                {
                    if (rez.rebra[i].from == vudilena_verchuna)
                    {
                        if (rez.elipsu[rez.rebra[i].from].lb_vershunu.Content.ToString().Equals("∞"))
                        {
                            vudilena_verchuna = rez.first;
                        }
                        else
                        {
                            if (int.Parse(rez.elipsu[rez.rebra[i].to].lb_vershunu.Content.ToString()) <
                                int.Parse(rez.elipsu[vudilena_verchuna].lb_vershunu.Content.ToString()))
                            {
                                value_versh.Add(int.Parse(rez.elipsu[rez.rebra[i].to].lb_vershunu.Content.ToString()));
                                id_rebra.Add(i);
                                nomer_vershunu.Add(rez.rebra[i].to);
                            }
                            if (!allEdges.Contains(rez.rebra[i]))
                            {
                                allEdges.Add(rez.rebra[i]);
                            }
                            if (!walkedEdges.Contains(rez.rebra[i]))
                            {
                                walkedEdges.Add(rez.rebra[i]);
                            }
                            if (!allVertex.Contains(rez.elipsu[rez.rebra[i].to]))
                            {
                                allVertex.Add(rez.elipsu[rez.rebra[i].to]);
                            }
                        }
                    }

                    if (rez.rebra[i].to == vudilena_verchuna)
                    {
                        if (rez.elipsu[rez.rebra[i].from].lb_vershunu.Content.ToString().Equals("∞"))
                        {
                            vudilena_verchuna = rez.first;
                        }
                        else
                        {
                            if (int.Parse(rez.elipsu[rez.rebra[i].from].lb_vershunu.Content.ToString()) <
                                int.Parse(rez.elipsu[vudilena_verchuna].lb_vershunu.Content.ToString()))
                            {
                                value_versh.Add(
                                    int.Parse(rez.elipsu[rez.rebra[i].from].lb_vershunu.Content.ToString()));
                                id_rebra.Add(i);
                                nomer_vershunu.Add(rez.rebra[i].from);
                            }
                            if (!allEdges.Contains(rez.rebra[i]))
                            {
                                allEdges.Add(rez.rebra[i]);
                            }
                            if (!walkedEdges.Contains(rez.rebra[i]))
                            {
                                walkedEdges.Add(rez.rebra[i]);
                            }
                            if (!allVertex.Contains(rez.elipsu[rez.rebra[i].to]))
                            {
                                allVertex.Add(rez.elipsu[rez.rebra[i].to]);
                            }
                        }
                    }
                }

                int min = 0;
                if (value_versh.Count == 0)
                {
                    vudilena_verchuna = rez.first;
                }

                min = value_versh.Min();

                for (int i = 0; i < id_rebra.Count; i++)
                {
                    if (value_versh[i] == min)
                    {
                        rez.rebra[id_rebra[i]].rebro.Stroke = redBrush;
                        vudilena_verchuna = nomer_vershunu[i];
                    }
                }
                var distrebra = rez.rebra.Where(x => id_rebra.Distinct().Contains(rez.rebra.IndexOf(x)));

                foreach (var edge in walkedEdges)
                {
                    node.Add(edge, fromEdge);
                }

                if (vudilena_verchuna == rez.first)
                {
                    break;
                }
            }
            /*foreach (var edge in allEdges)
            {
                node.Add(edge, vudilena_verchuna);
            }
            foreach (var edge in allEdges)
            {
                node.Add(edge, vudilena_verchuna);
            }*/
            allEdges = allEdges.OrderBy(x => x.from).ToList();

            //var startVertex = 
            
        }
        /// <summary>
        /// expand graph till <para name="to">to</para> or <param name="started">started</param>
        /// e.g.   4                          3
        ///       / \                        / \
        ///      /   \                      4   2
        /// 0---1     3   from 0 to 3      /     \
        ///      \  _/                    1       1
        ///       2                      / \     / \
        ///                             0   2   4   0
        /// </summary>
        /// <param name="node"></param>
        /// <param name="from"></param>
        /// <param name="started"></param>
        /// <param name="to"></param>
        /// <param name="fromLast"></param>
        /// <returns></returns>
        private void ExpandGraphRecursive(Node node, int from, int started, int to, int fromLast)
        {
            IList<Edge> possibleRoutes = fromLast >= 0
                                             ? rez.rebra.Where(
                                                 x => x.from == from && x.to != fromLast && x.to != started).ToList()
                                             : rez.rebra.Where(
                                                 x => x.from == from).ToList();
            foreach (var possibleRoute in possibleRoutes)
            {
                node.Add(possibleRoute, to);
                ExpandGraphRecursive(node, possibleRoute.to, started, to, possibleRoute.from);
            }
        }

        private IList<Edge> GetPath(Node node, int from)
        {
            var childFrom = GetChild(node, from);
            if (childFrom == null)
            {
                return null;
            }
            var result = new List<Edge>();

            while (childFrom.Parent != null)
            {
                result.Add(childFrom.Edge);
                childFrom = childFrom.Parent;
            }
            return result;
        }

        private Node GetChild(Node node, int from)
        {
            if (node.Edge.to == from)
            {
                return node;
            }
            foreach (var child in node.Childs)
            {
                return GetChild(child, from);
            }
            return null;
        }

        public class Node
        {
            public Edge Edge { get; set; }

            public Node Parent { get; set; }

            public IList<Node> Childs = new List<Node>();

            public bool ContainsFrom(int from)
            {
                if (Childs.Any(x => x.Edge.from == from))
                {
                    return true;
                }

                foreach (var child in Childs)
                {
                    return child.ContainsFrom(from);
                }
                return false;
            }

            public bool ContainsTo(int to)
            {
                if (Childs.Any(x => x.Edge.to == to))
                {
                    return true;
                }

                foreach (var child in Childs)
                {
                    return child.ContainsTo(to);
                }
                return false;
            }

            public void Add(Edge edge, int destination)
            {
                if (Childs.Any(x => x.Edge.from == edge.to || x.Edge.to == destination))
                {
                    return;
                }
                if (!Childs.Any(x => x.Edge.from == edge.from && x.Edge.to == edge.to))
                {
                    if (Edge.from == edge.from)
                    {
                        Childs.Add(new Node() {Edge = edge, Parent = this});
                        //return;
                    }
                    if (Childs.Any(x => x.Edge.to == edge.from))
                    {
                        if (
                            !Childs.First(x => x.Edge.to == edge.from).Childs.Any(
                                x => x.Edge.from == edge.from && x.Edge.to == edge.to))
                        {
                            var parent = Childs.First(x => x.Edge.to == edge.from);
                            parent.Childs.Add(new Node() {Edge = edge, Parent = parent});
                        }
                    }
                }
                if (ContainsTo(edge.from))
                {
                    foreach (var child in Childs)
                    {
                        child.Add(edge, destination);
                    }
                }
            }
        }

        protected void blueRectangle_MouseDown(object sender, RoutedEventArgs e)
        {


        }

        private void add_vershuna() //створення вершини
        {
            int StrokeThickness_ = 0;
            Color color_ = Colors.Blue;

            blueRectangle = new Ellipse()
                                {
                                    Height = 28,
                                    Width = 28,
                                    VerticalAlignment = System.Windows.VerticalAlignment.Top,
                                    HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
                                    Stroke = new SolidColorBrush(Colors.Black),
                                    StrokeThickness = StrokeThickness_,

                                    Fill = new RadialGradientBrush()
                                               {
                                                   RadiusX = 1,
                                                   RadiusY = 1,
                                                   GradientOrigin = new Point(0.7, 0.3),
                                                   GradientStops = new GradientStopCollection()
                                                                       {
                                                                           new GradientStop()
                                                                               {Color = Colors.White, Offset = 0},
                                                                           new GradientStop()
                                                                               {Color = color_, Offset = 1},
                                                                           new GradientStop()
                                                                               {Color = Colors.Aqua, Offset = 1}
                                                                       }
                                               }

                                };

            blueRectangle.Margin = new Thickness(x - 15, y - 15, 0, 0);
            blueRectangle.MouseDown += new MouseButtonEventHandler(blueRectangle_MouseDown);
            blueRectangle.MouseRightButtonDown += new MouseButtonEventHandler(add_redbrechko);
            blueRectangle.Name = "n" + id.ToString();

            lb_vershunu = new Label()
                              {
                                  VerticalAlignment = System.Windows.VerticalAlignment.Top,
                                  HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
                                  Width = 32,
                                  Height = 28
                              };
            lb_vershunu.Name = "l" + id.ToString();
            lb_vershunu.Uid = id.ToString();
            lb_vershunu.Margin = new Thickness(x - 15, y - 15, 0, 0);
            blueRectangle.ToolTip = blueRectangle.Name;
            lb_vershunu.MouseDown += new MouseButtonEventHandler(lb_vershunu_MouseDown);

        }
    }
}
